package org.zcl.govern.server.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zcl.govern.common.utils.StringUtils;
import org.zcl.govern.server.constant.NodeType;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import java.util.regex.Pattern;

/**
 * 服务治理平台的配置管理类
 * @author zhaocongliang
 */
public class Configuration {

    private static final Logger LOGGER = LoggerFactory.getLogger(Configuration.class);

    public static final String NODE_TYPE = "node.type";
    public static final String MASTER_NODE_SERVERS = "master.node.servers";
    public static final String NODE_ID = "node.id";

    private Configuration() {

    }

    private static class Singleton {

        static Configuration instance = new Configuration();

    }

    public static Configuration getInstance() {
        return Singleton.instance;
    }

    /**
     * 节点类型，master或者是slave
     */
    private String nodeType;
    /**
     * master节点机器列表
     */
    private String masterNodeServers;
    /**
     * 节点的id
     */
    private Integer nodeId;

    /**
     * 解析配置文件
     * @param configPath
     */
    public void parse(String configPath) throws ConfigurationException {
        try {
            LOGGER.info("going to parse configuration file......");

            // 加载配置文件
            Properties configProperties = loadConfigurationFile(configPath);

            // 解析和校验节点类型参数
            String nodeType = configProperties.getProperty(NODE_TYPE);
            if(validateNodeType(nodeType)) {
                this.nodeType = nodeType;
                LOGGER.debug("debug parameter value: node.type=" + nodeType);
            }

            // 解析和校验节点类型参数
            String nodeId = configProperties.getProperty(NODE_ID);
            if(validateNodeId(nodeId)) {
                this.nodeId = Integer.valueOf(nodeId);
                LOGGER.debug("debug parameter value: node.id=" + nodeId);
            }

            // 解析和校验master节点机器列表的参数
            String masterNodeServers = configProperties.getProperty(MASTER_NODE_SERVERS);
            if(validateMasterNodeServers(masterNodeServers)) {
                this.masterNodeServers = masterNodeServers;
                LOGGER.debug("debug parameter value: master.node.servers=" + masterNodeServers);
            }
        } catch(IllegalArgumentException e) {
            throw new ConfigurationException("parsing config file error", e);
        } catch (FileNotFoundException e) {
            throw new ConfigurationException("parsing config file error", e);
        } catch (IOException e) {
            throw new ConfigurationException("parsing config file error", e);
        }
    }

    /**
     * 加载配置文件
     * @param configPath 配置文件地址
     * @return 放入内存的配置
     */
    private Properties loadConfigurationFile(String configPath) throws IOException, IllegalArgumentException {
        File configFile = new File(configPath);

        if(!configFile.exists()) {
            throw new IllegalArgumentException("config file " + configPath + " doesn't exist......");
        }

        Properties configProperties = new Properties();
        FileInputStream configFileInputStream = new FileInputStream(configFile);
        try {
            configProperties.load(configFileInputStream);
        } finally {
            configFileInputStream.close();
        }

        LOGGER.info("successfully loading configuration from file......");

        return configProperties;
    }

    /**
     * 校验节点类型参数
     * @param nodeType 节点类型
     * @return 校验是否通过
     * @throws IllegalArgumentException
     */
    private Boolean validateNodeType(String nodeType) throws IllegalArgumentException {
        if(StringUtils.isEmpty(nodeType)) {
            throw new IllegalArgumentException("node.type cannot be empty......");
        } else if(!NodeType.MASTER.equals(nodeType)
                && !NodeType.SLAVE.equals(nodeType)) {
            throw new IllegalArgumentException("node.type must be master or slave......");
        }
        return true;
    }

    /**
     * 校验master节点机器列表参数
     * @param masterNodeServers master节点机器列表
     * @return 校验是否通过
     * @throws IllegalArgumentException
     */
    private Boolean validateMasterNodeServers(String masterNodeServers) throws IllegalArgumentException {
        if(StringUtils.isEmpty(masterNodeServers)) {
            throw new IllegalArgumentException("master.node.servers cannot be empty.....");
        }

        String[] masterNodeServersArray = masterNodeServers.split(",");
        if(masterNodeServersArray == null || masterNodeServersArray.length == 0) {
            throw new IllegalArgumentException("master.node.servers cannot be empty.....");
        }

        final String masterNodeServerRegex = "(\\d+):(\\d+\\.\\d+\\.\\d+\\.\\d+):(\\d+):(\\d+):(\\d+)";

        for(String masterNodeServer : masterNodeServersArray) {
            Boolean isMatch = Pattern.matches(masterNodeServerRegex, masterNodeServer);
            if(!isMatch) {
                throw new IllegalArgumentException("master.node.servers parameter has a wrong pattern: " + masterNodeServer);
            }
        }

        return true;
    }

    /**
     * 校验节点id参数
     * @param nodeId
     * @return
     */
    private boolean validateNodeId(String nodeId) {
        if(StringUtils.isEmpty(nodeId)) {
            throw new IllegalArgumentException("node.id cannot be empty......");
        }

        final String nodeIdRegex = "(\\d+)";
        Boolean isMatch = Pattern.matches(nodeIdRegex, nodeId);
        if(!isMatch) {
            throw new IllegalArgumentException("node.id must be a number......");
        }

        return true;
    }
    /**
     * 获取节点类型
     * @return
     */
    public String getNodeType() {
        return nodeType;
    }

}
